//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <Winhack.h>
#include "CBasicFileSystem.h"
#include "CBasicDirectory.h"
#include <_CKtfsFileSystem.cpp>
#include <Aura.h>

#define FILESYSTEM_CLUSTERSIZE  (4096)

static IDeviceDriver *s_pKtfsDriver = NULL;
static Aura_Handle s_hModule = NULL;

EXTERN IDeviceDriver* CDECL CreateKtfs(uint_t uDeviceNo, void *pvParameter);

ECode CKtfsFileSystem::Initialize(
        /* [in] */ wchar_t *wcsDisk)
{
    assert(NULL != wcsDisk);

    m_pDiskName = (wchar_t *)Aura_malloc(sizeof(wchar_t) * (wcslen(wcsDisk)+1));
    if (NULL == m_pDiskName) {
        return E_OUT_OF_MEMORY;
    }
    //wcscpy(m_pDiskName, wcsDisk + 2);
    wcscpy(m_pDiskName, L"\\");

    return NOERROR;
}

CKtfsFileSystem::~CKtfsFileSystem()
{
    if (NULL != m_pDiskName) {
        Aura_free(m_pDiskName);
        m_pDiskName = NULL;
    }
    if (NULL != m_pRootDir) {
        m_pRootDir->Release();
    }
}

ECode CKtfsFileSystem::Sync()
{
    return NOERROR;
}

ECode CKtfsFileSystem::GetRoot(
    /* [out] */ IBasicDirectory ** piRoot)
{
    CBasicDirectory * pRootDir = NULL;
    ECode ec = NOERROR;

    if (NULL == piRoot) {
        return E_INVALID_ARGUMENT;
    }

    if (NULL != pRootDir) {
        *piRoot = pRootDir;
        pRootDir->AddRef();
        return NOERROR;
    }

    pRootDir = new CBasicDirectory(NULL);
    if (NULL == pRootDir) {
        ec = E_OUT_OF_MEMORY;
        goto E_FAIL_EXIT;
    }

    ec = pRootDir->Initialize(m_pDiskName);
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    pRootDir->AddRef(); // for filesystem sellf.
    *piRoot = pRootDir;

    m_pRootDir = static_cast<IBasicDirectory *>(pRootDir);
    m_pRootDir->AddRef(); // for caller.

    return NOERROR;

E_FAIL_EXIT:
    if (NULL != pRootDir) {
        delete pRootDir;
    }
    return ec;
}

ECode CKtfsFileSystem::Lookup(
    /* [in] */ WString pathname,
    /* [out] */ IBasicFile * * piBasicFile)
{
    if (NULL == m_pRootDir) {
        return E_INVALID_OPERATION;
    }
    return m_pRootDir->Lookup(pathname, piBasicFile);
}

ECode CKtfsFileSystem::BindDriver(
    /* [in] */ WString wstrDevName)
{
    return NOERROR;
}

ECode CKtfsFileSystem::UnbindDriver()
{
    return NOERROR;
}

ECode CKtfsFileSystem::GetStat(
        /* [out] */ FileSystemStat * pFileSystemStat)
{
    UInt64 diskTotalSize = 0;
    UInt64 diskFreeSize  = 0;
    BOOL bSuccess = FALSE;

    assert(NULL != m_pDiskName);

    if (NULL == pFileSystemStat) {
        return E_INVALID_ARGUMENT;
    }

    bSuccess = GetDiskFreeSpaceExW(NULL,
                            NULL,
                            (PULARGE_INTEGER)&diskTotalSize,
                            (PULARGE_INTEGER)&diskFreeSize);
    if (!bSuccess) {
        return ECODE_FROM_WIN32(GetLastError());
    }

    pFileSystemStat->clusterSize   = FILESYSTEM_CLUSTERSIZE;
    pFileSystemStat->totalClusters = (UInt32)(diskTotalSize / pFileSystemStat->clusterSize);
    pFileSystemStat->freeClusters  = (UInt32)(diskFreeSize / pFileSystemStat->clusterSize);
    pFileSystemStat->fatType = FatType_FAT32;

    return NOERROR;
}

extern "C" ECode KtfsInitialize(void)
{
    IDeviceDriver *pDriver = NULL;

    pDriver = CreateKtfs(0, NULL);
    if (NULL == pDriver) {
        return E_OUT_OF_MEMORY;
    }
    s_pKtfsDriver = pDriver;

    return NOERROR;
}

extern "C" void KtfsDestroy(void)
{
    if (NULL != s_pKtfsDriver)
        s_pKtfsDriver->Release();
}

extern "C"  IDeviceDriver * GetFileSystemService()
{
    assert(NULL != s_pKtfsDriver);
    return s_pKtfsDriver;
}

extern "C" ECode LoadModules(void)
{
    ECode ec = NOERROR;
    Aura_Address address = 0;;

    ec = AuraModule_Load((Aura_PWChar)L"ezregsvr.dll", 0, &s_hModule);
    if (FAILED( ec)) {
    #if _DEBUG
        Aura_printf("Failed loadmodules\n");
    #endif
        return ec;
    }

    ec = AuraModule_GetProcAddressByName(s_hModule, (Aura_PChar)"loadService", &address);
    if (FAILED(ec)) {
        AuraModule_Unload(s_hModule);
        s_hModule = NULL;
    #if _DEBUG
        Aura_printf(" <%s> failed .(ec = 0x%x).\n",__FUNCTION__,ec);
    #endif
        return ec;
    }

    ((FARPROC)address)();
    return NOERROR;
}

extern "C" ECode UnLoadModule(void)
{
    if (NULL != s_hModule)
        return AuraModule_Unload(s_hModule);

    return NOERROR;
}

